﻿using DevComponents.AdvTree;
using HPSocketCS;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Net;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;
using NS_Log;
using CommonTools;
using UtilLib.Msg;
using Common;

namespace ControlServer
{
    public partial class ControllerForm : Form
    {
        HPSocketCS.TcpServer server = new HPSocketCS.TcpServer();
        HPSocketCS.Extra<ClientInfo> extra = new HPSocketCS.Extra<ClientInfo>();
        List<ClientInfo> clients = new List<ClientInfo> { };

        public enum Client_Action
        {
            CA_ADD,
            CA_REMOVE,
            CA_MODIFY,
        }

        public ControllerForm()
        {
            InitializeComponent();
        }

        private void ControllerForm_Load(object sender, EventArgs e)
        {
            //绑定监听事件
            server.OnAccept += new TcpServerEvent.OnAcceptEventHandler(OnAccept);
            //server.OnSend += new TcpServerEvent.OnSendEventHandler(OnSend);
            server.OnReceive += new TcpServerEvent.OnReceiveEventHandler(OnReceive);
            server.OnClose += new TcpServerEvent.OnCloseEventHandler(OnClose);
            server.OnShutdown += new TcpServerEvent.OnShutdownEventHandler(OnShutdown);

            MyLog.Instance.SetLogWin(this.rtb_message);//设置日志显示窗口（选做，且只设置一次即可）
        }

        private void ControllerForm_FormClosing(object sender, FormClosingEventArgs e)
        {
            log("[FormClosing]");

            //关闭窗口停止服务
            StopServer();
        }

        //显示日志
        private void log(string msg)
        {
            MyLog.Instance.log(msg); //写日志，同时显示日志（如果执行过SetLogWin）
        }

        #region SOCKET事件

        // 接受客户端连接
        HandleResult OnAccept(IntPtr connId, IntPtr pClient)
        {
            string ip = string.Empty;
            ushort port = 0;
            // 设置附加数据
            ClientInfo clientInfo = new ClientInfo();
            clientInfo.ConnId = connId;
            if (server.GetRemoteAddress(connId, ref ip, ref port))
            {
                clientInfo.IpAddress = ip;
                clientInfo.Port = port;
                clientInfo.ConnTime = DateTime.Now;
                //添加终端
                Update_ClientList(clientInfo, Client_Action.CA_ADD);
                log(string.Format("[OnAccept,{0}] -> ({1}:{2})", connId, ip.ToString(), port));
            }
            else
            {
                log(string.Format("[OnAccept,{0}] -> Server_GetClientAddress() Error", connId));
            }

            return HandleResult.Ok;
        }

        //服务器发完数据（未注册本事件，不启用）
        HandleResult OnSend(IntPtr connId, byte[] bytes)
        {
            try
            {
                byte[] bytex = new byte[bytes.Length - 4];
                for (int i = 4; i < bytes.Length; i++)
                {
                    bytex[i - 4] = bytes[i];
                }
                ClientInfo clientInfo = extra.Get(connId);
                // 服务器发数据了
                log(string.Format("[OnSend,{0}-{1}:{2}] -> Content:{3} ;Length:({4} bytes)", connId, clientInfo.IpAddress, clientInfo.Port, Encoding.UTF8.GetString(bytex), bytex.Length));
            }
            catch (Exception exp)
            {
                log(string.Format("[OnSend Exception] -> {0}," + connId, exp.Message));
            }

            return HandleResult.Ok;
        }

        //服务器收到数据
        HandleResult OnReceive(IntPtr connId, byte[] bytes)
        {
            try
            {
                string data = BitConverter.ToString(bytes);
                log(string.Format("[OnReceive,{0}] -> Length:{1};Content:{2}", connId, bytes.Length, data));

                // 获取附加数据
                ClientInfo clientInfo = extra.Get(connId);
                if (clientInfo != null)
                {
                    //合并数据
                    clientInfo.buffer.AddRange(bytes);
                    //拆出一个完整包
                    byte[] pack = GetOneFullPack(clientInfo.buffer);
                    //分析该包
                    Datagram datagram = new Datagram(pack);
                    //处理数据
                    ProcessMsg(clientInfo, datagram);
                }
                else
                {
                    log(string.Format("[OnReceive,{0}] -> no found the connID)", connId));
                }
                //if (SendData(connId, bytes, bytes.Length))
                //{
                //    return HandleResult.Ok;
                //}
                //return HandleResult.Error;
                return HandleResult.Ok;
            }
            catch (Exception)
            {

                return HandleResult.Ignore;
            }
        }

        //客户端断开连接
        HandleResult OnClose(IntPtr connId, SocketOperation enOperation, int errorCode)
        {
            if (errorCode == 0)
                log(string.Format("[OnClose,{0}]", connId));
            else
                log(string.Format("[OnError,{0}] -> OP:{1},CODE:{2}", connId, enOperation, errorCode));

            //删除终端
            ClientInfo clientInfo = extra.Get(connId);
            Update_ClientList(clientInfo, Client_Action.CA_REMOVE);

            return HandleResult.Ok;
        }

        // 服务关闭
        HandleResult OnShutdown()
        {
            log("[OnShutdown]");
            return HandleResult.Ok;
        }
        #endregion

        #region 更新终端显示列表

        /// <summary>
        /// 更新终端显示列表
        /// </summary>
        /// <param name="client">终端信息</param>
        /// <param name="action">0--添加终端，1--删除终端，2--删除终端</param>
        private void Update_ClientList(ClientInfo client, Client_Action action = Client_Action.CA_ADD)
        {
            if (this.advTree1.IsDisposed)
                return;

            try
            {
                if (this.advTree1.InvokeRequired)
                {
                    var de = new Action<ClientInfo, Client_Action>(Update_ClientList);//Action为.net为我们定义好的泛型委托，他可以有0个到16个输入参数，但无返回值
                    this.advTree1.Invoke(de, new object[] { client, action });
                }
                else
                {
                    if (action == Client_Action.CA_ADD)
                    {
                        clientAddTree(client);
                    }
                    else if (action == Client_Action.CA_REMOVE)
                    {
                        clientRemoveTree(client);
                    }
                    else
                    {
                        clientModifyTree(client);
                    }
                }
            }
            catch (Exception ex)
            {
                log("Update_ClientTree Exception: " + ex.Message);
            }
        }

        //添加终端
        private void clientAddTree(ClientInfo client)
        {
            log(string.Format("[clientAdd] -> {0}", client.ConnId));
            extra.Set(client.ConnId, client);

            //添加到内存列表
            clients.Add(client);

            //添加到显示界面
            Node node = new Node();
            node.ImageIndex = 0;
            node.Text = client.ConnId.ToString();
            node.Tag = client;
            node.CheckBoxVisible = true;
            node.Cells.Add(new Cell(client.IpAddress));
            node.Cells.Add(new Cell(client.Port.ToString()));
            advTree1.Nodes.Insert(0, node);
        }

        //删除终端
        private void clientRemoveTree(ClientInfo client)
        {
            log(string.Format("[clientRemove] -> {0}", client.ConnId));
            extra.Remove(client.ConnId);

            foreach (ClientInfo c in clients)
            {
                if (c.ConnId == client.ConnId)
                {
                    //内存列表删除
                    clients.Remove(c);
                    break;
                }
            }

            foreach (Node node in advTree1.Nodes)
            {
                if (node.Text == client.ConnId.ToString())
                {
                    //从显示界面删除
                    advTree1.Nodes.Remove(node);
                    break;
                }
            }
        }

        //修改终端
        private void clientModifyTree(ClientInfo client)
        {
            log(string.Format("[clientModify] -> {0}", client.ConnId));
            extra.Set(client.ConnId, client);

            //修改内存列表
            for (int i = 0; i < clients.Count; i++)
            {
                ClientInfo c = clients[i];
                if (clients[i].ConnId == client.ConnId)
                {
                    clients[i] = client;
                    break;
                }
            }

            //修改显示界面
            for (int i = 0; i < advTree1.Nodes.Count; i++)
            {
                if (advTree1.Nodes[i].Text == client.ConnId.ToString())
                {
                    advTree1.Nodes[i].ImageIndex = 1;
                    advTree1.Nodes[i].Cells[1].Text = client.registerCode;
                    advTree1.Nodes[i].Cells[2].Text = client.deviceId;
                    break;
                }
            }
        }

        #endregion

        #region 服务器函数
        private void StartServer()
        {
            //服务启动
            try
            {
                string ip = server.IpAddress = "0.0.0.0";
                int port = server.Port = 5300;
                if (server.Start())
                {
                    log(string.Format("Server Start OK,Port:{0}", port));
                }
                else
                {
                    log(string.Format("Server Start Error,:{0}\n{1}", server.ErrorCode, server.ErrorMessage));
                }
            }
            catch (Exception ex)
            {
                log("Server Start Exception: " + ex.Message);
            }
        }

        private void StopServer()
        {
            //服务停止
            try
            {
                if (server.Stop())
                {
                    log("Server Stop OK");
                }
                else
                {
                    log(string.Format("Server Stop Error -> {0}\n{1}", server.ErrorCode, server.ErrorMessage));
                }
            }
            catch (Exception ex)
            {
                log("Server Stop Exception: " + ex.Message);
            }
        }

        private bool SendData(IntPtr connId,byte [] data)
        {
            //发送数据
            try
            {
                return server.Send(connId, data,data.Length);

            }
            catch (Exception ex)
            {
                log("send data Exception: " + ex.Message);
                return false;
            }
        }

        /// <summary>
        /// 取出一个完整包，同时从输入数据里删除该包
        /// </summary>
        /// <param name="inData">输入数据</param>
        /// <returns>得到的完整包数据，null表示没有取到</returns>
        byte[] GetOneFullPack(List<byte> inData)
        {
            int b=0;
            int e=0;

            //找到包头
            while(true)
            {
                b = inData.IndexOf(0xFA, b);
                if (b >= 0 && b < inData.Count - 2)
                {
                    if (inData[b + 1] == 0xFB) //找到包头了
                        break;
                    else
                    {
                        b++; //继续找下一个字节
                        if (b >= inData.Count - 1)
                        {
                            //到数据的结尾了
                            b = -1;
                            break;
                        }
                    }
                }
                else
                {
                    //找不到
                    b = -1;
                    break;
                }
            }

            //找到包尾
            e = b + 1;
            while (true)
            {
                e = inData.IndexOf(0xFC, e);
                if (e >= 0 && e < inData.Count - 1)
                {
                    if (inData[e + 1] == 0xFD) //找到包尾了
                        break;
                    else
                    {
                        e++; //继续找下一个字节
                        if (e >= inData.Count - 1)
                        {
                            //到数据的结尾了
                            e = -1;
                            break;
                        }
                    }
                }
                else
                {
                    //找不到
                    e = -1;
                    break;
                }
            }

            if (b >= 0 && e > b) //取一个完整包
            {
                byte[] one= inData.GetRange(b, e - b + 2).ToArray();
                inData.RemoveRange(0, e + 2);
                return one;
            }

            return null;
        }

        #endregion

        #region 界面事件

        private void btnSend_Click(object sender, EventArgs e)
        {
            //发送消息
            try
            {
                string sendContent = txtMsg.Text;
                if (sendContent.Length < 1)
                {
                    throw new Exception(" write no content");
                }
                if (advTree1.Nodes.Count < 1)
                {
                    throw new Exception(" have no client");
                }
                byte[] sendBytes = Encoding.UTF8.GetBytes(sendContent);

                bool hck = false;
                for (int i = 0; i < advTree1.Nodes.Count; i++)
                {
                    IntPtr connId = (IntPtr)Convert.ToInt32(advTree1.Nodes[i].Cells[0].Text);
                    if (advTree1.Nodes[i].Checked)
                    {
                        hck = true;
                        server.Send(connId, sendBytes, sendBytes.Length);
                    }
                }
                if (!hck)
                {
                    throw new Exception(" choose no client");
                }
                txtMsg.Text = string.Empty;
            }
            catch (Exception exc)
            {
                log(string.Format("Send Failed ->{0}", exc.Message));
            }
        }

        private void checkBoxAll_CheckedChanged(object sender, EventArgs e)
        {
            bool chk = checkBoxAll.Checked;
            foreach (Node node in advTree1.Nodes)
            {
                node.Checked = chk;
            }
        }
        private void btnCheckedDiscon_Click(object sender, EventArgs e)
        {
            //断开选择的终端            
            for (int i = advTree1.Nodes.Count - 1; i >= 0; i--)
            {
                if (advTree1.Nodes[i].Checked)
                {
                    server.Disconnect((IntPtr)((ClientInfo)advTree1.Nodes[i].Tag).ConnId, true);
                    advTree1.Nodes.Remove(advTree1.Nodes[i]);
                }
            }
        }
        private void 查看ToolStripMenuItem_Click(object sender, EventArgs e)
        {

        }

        private void 断开ToolStripMenuItem_Click(object sender, EventArgs e)
        {
            if (advTree1.SelectedNode != null)
            {
                server.Disconnect((IntPtr)((ClientInfo)advTree1.SelectedNode.Tag).ConnId, true);
            }

        }

        private void test1ToolStripMenuItem_Click(object sender, EventArgs e)
        {
            ClientInfo client = new ClientInfo();
            client.buffer.Add(1);
            IntPtr connId = (IntPtr)999;
            extra.Set(connId, client);

            ClientInfo client1 = extra.Get(connId);
            client1.buffer.Add(2);

            ClientInfo client2 = extra.Get(connId);
            client2.buffer.Add(3);
        }

        #endregion

        bool bFirstStart = true;
        int iTick = 0;
        private void timer1_Tick(object sender, EventArgs e)
        {
            iTick++;
            if (iTick > 100)
                iTick = 1;

            if (bFirstStart)
            {
                bFirstStart = false;
                StartServer();
            }

            //三秒结束验证终端Legal，作断开处理
            if (iTick % 3 == 0)
            {
                return;//临时禁止
                try
                {
                    foreach (ClientInfo client in clients)
                    {
                        if (!client.Legal)
                        {
                            if ((DateTime.Now - client.ConnTime).Seconds >= 3)
                            {
                                log(string.Format("[Disconnect illegal connecting] -> {0}", client.ConnId));
                                //string ret = new Datagram(Codes.getValue(Codes.InstructCode.CONN_REP), "", "", "", "ERROR;Check Failed!").getMsg();
                                //byte[] retbytes = Encoding.UTF8.GetBytes(ret);
                                //server.Send(client.ConnId, retbytes, retbytes.Length);
                                server.Disconnect(client.ConnId, true);
                                clients.Remove(client);
                            }
                        }
                    }
                }
                catch (Exception ex)
                {
                    log(ex.Message);
                }
            }

        }

        /// <summary>
        /// 处理终端消息
        /// </summary>
        /// <param name="clientInfo">设备连接信息</param>
        /// <param name="datagram">数据包</param>
        private void ProcessMsg(ClientInfo clientInfo,Datagram datagram)
        {
            //校验不正确的数据，直接丢弃
            if (datagram.isVaild != 0)
            {
                log(string.Format("[ProcessMsg,{0}] -> data Check fail,error[{1}]", clientInfo.ConnId, datagram.isVaild));
                //发送应答数据
                SendData(clientInfo.ConnId, datagram.getAckCode(20));

                return;
            }

            //未登录设备，必须先登录，处理登录消息
            if (!clientInfo.Legal)
            {
                //验证终端是否合法
                if (datagram.cmdCode == 0x1000)
                {
                    log(string.Format("[ProcessMsg,{0}] -> login Success", clientInfo.ConnId));
                    //发送应答数据
                    SendData(clientInfo.ConnId, datagram.getAckCode(0));

                    //解析数据
                    clientInfo.Legal = true;
                    clientInfo.registerCode = System.Text.Encoding.UTF8.GetString(datagram.content, 0, 20);
                    clientInfo.deviceId = BitConverter.ToString(datagram.content, 20,8).Replace("-", "");
                    clientInfo.ver=datagram.content[28];

                    //更新终端
                    Update_ClientList(clientInfo, Client_Action.CA_MODIFY);
                }
                else
                {
                    log(string.Format("[ProcessMsg,{0}] -> error,unlogin device", clientInfo.ConnId));
                    //发送应答数据
                    SendData(clientInfo.ConnId, datagram.getAckCode(10));
                }

                return;
            }

            //正常数据消息
            switch (datagram.cmdCode)
            {
                case 0x1000: //登录
                    {
                        log(string.Format("[ProcessMsg,{0}] -> login duplication", clientInfo.ConnId));
                        //发送应答数据
                        SendData(clientInfo.ConnId, datagram.getAckCode(11));
                    }
                    break;
                case 0x1100: //心跳
                    {
                        log(string.Format("[ProcessMsg,{0}] -> beat", clientInfo.ConnId));
                        //发送应答数据
                        SendData(clientInfo.ConnId, datagram.getAckCode(0));
                    }
                    break;
                case 0x2001: //参数设置的回应
                    {
                        log(string.Format("[ProcessMsg,{0}] -> set parameter", clientInfo.ConnId));
                    }
                    break;
                case 0x2101: //参数获取的回应
                    {
                        log(string.Format("[ProcessMsg,{0}] -> get parameter", clientInfo.ConnId));
                    }
                    break;
                case 0x3000: //运行状态上报
                    {
                        log(string.Format("[ProcessMsg,{0}] -> running status", clientInfo.ConnId));
                        //发送应答数据
                        SendData(clientInfo.ConnId, datagram.getAckCode(0));
                    }
                    break;
                case 0x3100: //故障数据上报
                    {
                        log(string.Format("[ProcessMsg,{0}] -> fault data", clientInfo.ConnId));
                        //发送应答数据
                        SendData(clientInfo.ConnId, datagram.getAckCode(0));
                    }
                    break;
                case 0x3200: //统计数据上报
                    {
                        log(string.Format("[ProcessMsg,{0}] -> statics status", clientInfo.ConnId));
                        //发送应答数据
                        SendData(clientInfo.ConnId, datagram.getAckCode(0));
                    }
                    break;
                case 0x4001: //远程控制的回应
                    {
                        log(string.Format("[ProcessMsg,{0}] -> remote control", clientInfo.ConnId));
                    }
                    break;
            }
        }

    }
}
